package com.crazymaker.demo.proxy.FeignMock;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.LinkedHashMap;
import java.util.Map;

class SimpleInvocationHandler implements InvocationHandler
{
    private Map<String, MethodHandler> dispatch;


    public static <T> T newInstance(Class<T> clazz)
    {
        Annotation controllerAnno = clazz.getAnnotation(RestController.class);
        if (controllerAnno == null)
        {
            return null;
        }

        SimpleInvocationHandler invokeHandler = new SimpleInvocationHandler();
        invokeHandler.dispatch = new LinkedHashMap<>();

        for (Method method : clazz.getMethods())
        {
            Annotation methodAnnotation =
                    method.getAnnotation(GetMapping.class);
            if (methodAnnotation == null)
            {
                continue;
            }
            String url = ((GetMapping) methodAnnotation).name();
            String host = ((RestController) controllerAnno).value();
            SimpleMethodHandler handler = new SimpleMethodHandler(host, url);
            invokeHandler.dispatch.put(method.getName(), handler);

        }
        T proxy = (T) Proxy.newProxyInstance(
                clazz.getClassLoader(),
                new Class<?>[]{clazz}, invokeHandler);
        return proxy;
    }


    @Override
    public Object invoke(
            Object proxy,
            Method method, Object[] args) throws Throwable
    {

        if ("equals".equals(method.getName()))
        {
            Object other = args.length > 0 && args[0] != null ? args[0] : null;
            return equals(other);
        } else if ("hashCode".equals(method.getName()))
        {
            return hashCode();
        } else if ("toString".equals(method.getName()))
        {
            return toString();
        }


        MethodHandler methodHandler = dispatch.get(method.getName());
        return methodHandler.invoke(args);
    }
}
